BlockUtils.parseToken   A
last analyzed

Complexity

Conditions 4

Size

Total Lines 15
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 4

Importance

Changes 0
Metric Value
eloc 10
dl 0
loc 15
ccs 8
cts 8
cp 1
rs 9.9
c 0
b 0
f 0
cc 4
crap 4
1
/*jslint node: true, nomen: true, regexp: true, plusplus: true */
2 1
(function () {
3
4
    "use strict";
5
6 1
    const   request     = require("request"),
7
            RateLimiter = require("limiter").RateLimiter;
8
9
    class BlockUtils {
10
11
        constructor(apiUrl, magicToken, signalApiUrl, perSecondRateLimit)
12
        {
13 1
            this.API_URL = apiUrl;
14 1
            this.MAGIC_TOKEN = magicToken;
15 1
            this.SIGNAL_API_URL = signalApiUrl;
16 1
            this.limiter = new RateLimiter(perSecondRateLimit, 'second');
17
        }
18
19
        /**
20
         * Allow to use callback-style methods with promises
21
         * @param {Array}       args            Original function arguments
22
         * @param {Number}      optionsOffset   Expected offset of the options object in the arguments
23
         * @callback
24
         * @private
25
         */
26
        _handlePromises(args, optionsOffset, callback) {
27 127
            let fCallback = args[args.length - 1];
28 127
            const checkArgsAndGo = (options = {}) => {
29 127
                if (args[optionsOffset] !== fCallback) {
30 112
                    options = args[optionsOffset];
31
                }
32 127
                callback(options, fCallback);
33
            };
34 127
            if (typeof fCallback === "function") {
35 22
                return checkArgsAndGo();
36
            }
37 105
            return new Promise((resolve, reject) => {
38 105
                fCallback = (err, res) => {
39 105
                    if (err) { return reject(err); }
40 83
                    return resolve(res);
41
                };
42 105
                checkArgsAndGo();
43
            });
44
        }
45
46
        /**
47
         * Make and return the call to the API
48
         * @param endpoint
49
         * @param callback
50
         * @private
51
         */
52
        call() {
53 38
            return this._handlePromises(arguments, 1, ({
54
                useSignalAPI = false,
55
                method = "GET",
56
                body = null
57
            } = {}, callback) => {
58 38
                this.limiter.removeTokens(1, () => {
59 38
                    request({
60
                        method: method,
61
                        url: ((useSignalAPI) ? this.SIGNAL_API_URL : this.API_URL) + arguments[0],
62
                        headers: {"magic": this.MAGIC_TOKEN},
63
                        body: body
64
                    }, (err, result, body) => {
65 38
                        try {
66 38
                            const tBody = JSON.parse(body);
67
68 21
                            return callback(null, tBody);
69
                        } catch (e) {
70
                            // Exceptions for plain text responses
71 17
                            if (body === "success") {
72 14
                                return callback(null, body);
73 3
                            } else if (body === "fail") {
74
                                return callback(new Error("FAIL"));
75
                            }
76
77 3
                            return callback(e, body);
78
                        }
79
                    });
80
                });
81
            });
82
        }
83
84
        /**
85
         * Parse and format a token pair
86
         * @param tokenStr String containing the token (ie. "XRP/BTC", "AEON", "USD-LTC", ...)
87
         * @returns {*} Structure with base & token values (default base is BTC)
88
         * @private
89
         */
90
        parseToken(tokenStr) {
91
            // Token is already parsed
92 33
            if (typeof tokenStr === "object") { return tokenStr; }
93
94
            // Check token format
95 27
            if (tokenStr.indexOf("/") > -1) { // Classic representation
96 22
                const [token, base] = tokenStr.split("/");
97 22
                return {base, token};
98 5
            } else if(tokenStr.indexOf("-") > -1) { // Inversed one
99 3
                const [base, token] = tokenStr.split("-");
100 3
                return {base, token};
101
            } else { // Raw token without attached base
102 2
                return {base: "BTC", token: tokenStr};
103
            }
104
        }
105
106
        /**
107
         * Create a new fake device to use with Blockfolio & return the Blockfolio instance
108
         * @callback
109
         * @private
110
         */
111
        generateClientToken() {
112 1
            return parseInt(Math.random().toString().substring(2)).toString(12);
113
        }
114
    }
115
116 1
    module.exports = BlockUtils;
117
118
})();